/*
 * WebAccess.java
 *
 * Copyright(c) 2010
 * Michael Kroez
 * kroez@studiorutton.de
 *
 * All rights reserved.
 *
 * $Id$
 * 
 */

package de.studiorutton.access;

import java.io.BufferedInputStream;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;

import de.studiorutton.access.WebspaceException.ErrorCode;

import android.util.Log;

public class WebAccess {

	private static final String TAG = "access";
	private static final int BUF_SIZE = 8192;

	private FileLocation fileLocation;
	private HttpClient client;
	

	public WebAccess(FileLocation fileLocation) {
		this.fileLocation = fileLocation;
	}

	public FileLocation getLocation() {
		return fileLocation;
	}

	public void setFileLocation(FileLocation fileLocation) {
		this.fileLocation = fileLocation;
	}

	public FileProperties evaluateResponseHeaders(HttpResponse response)
			throws WebspaceException {
		FileProperties fp = new FileProperties();

		// Header[] headers = response.getAllHeaders();
		// int i;
		// for( i = 0; i < headers.length; i++ ) {
		// Log.d(TAG, "Name:" + headers[i].getName() + " Value:" +
		// headers[i].getValue());
		// }

		Header header = response.getFirstHeader("content-length");
		if (header == null) {
			Log.e(TAG, "Content-Length header not found.");
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_FIND_CONTENT_LENGTH, fileLocation.createFileURI());
		} else
			fp.contentLength = Long.parseLong(header.getValue());

		header = null;
		header = response.getFirstHeader("content-type");
		if (header == null) {
			Log.e(TAG, "Content-Type header not found.");
			throw new WebspaceException(ErrorCode.ERROR_CANNOT_FIND_CONTENT_TYPE, fileLocation.createFileURI());
		} else
			fp.contentType = header.getValue();

		header = null;
		header = response.getFirstHeader("content-encoding");
		if (header == null)
			fp.contentEncoding = "identity";
		else
			fp.contentEncoding = header.getValue();

		header = null;
		header = response.getFirstHeader("last-modified");
		if (header == null) {
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_FIND_LAST_MODIFIED, fileLocation.createFileURI());
		}
		try {
			fp.lastModified = DateUtils.parseDate(header.getValue());
		} catch (DateParseException e) {
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_PARSE_LAST_MODIFIED, fileLocation.createFileURI(), e.getLocalizedMessage());
		}
		// Log.d(TAG, "Last-Modified date is " + fp.lastModified.toLocaleString());

		return fp;
	}

	public FileProperties getFileProperties() throws WebspaceException {
		client = new DefaultHttpClient();
		HttpHead head = new HttpHead(fileLocation.createFileURI());
		head.addHeader("Accept-Encoding", "gzip, compress");
		HttpResponse response;
		try {
			response = client.execute(head);
		} catch (ClientProtocolException e) {
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_REACH_REMOTE_SERVER, fileLocation.baseURL);
		} catch (IOException e) {
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_REACH_REMOTE_SERVER, fileLocation.baseURL);
		}
		int responseCode = response.getStatusLine().getStatusCode();
		if ( responseCode != HttpStatus.SC_OK) {
			String r = "" + responseCode;
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_REACH_REMOTE_FILE, fileLocation.createFileURI(), r);
		}

		FileProperties fp = evaluateResponseHeaders(response);
		shutdownConnection();
		return fp;
	}

	public InputStream getInputStream(IProgressListener pl)
			throws WebspaceException {
		client = new DefaultHttpClient();
		HttpGet get = new HttpGet(fileLocation.createFileURI());
		get.addHeader("Accept-Encoding", "gzip, compress");
		HttpResponse response;
		try {
			response = client.execute(get);
		} catch (ClientProtocolException e) {
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_REACH_REMOTE_SERVER, fileLocation.baseURL );
		} catch (IOException e) {
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_REACH_REMOTE_SERVER, fileLocation.baseURL );
					
		}
		int responseCode = response.getStatusLine().getStatusCode();
		if ( responseCode != HttpStatus.SC_OK) {
			String r = "" + responseCode;
			throw new WebspaceException( ErrorCode.ERROR_CANNOT_REACH_REMOTE_FILE, fileLocation.createFileURI(), r);
		}

		FileProperties fp = evaluateResponseHeaders(response);

		InputStream in;
		try {
			in = response.getEntity().getContent();
		} catch (IllegalStateException e) {
			throw new WebspaceException(
					ErrorCode.ERROR_CANNOT_REACH_REMOTE_FILE, fileLocation.createFileURI(), e.getLocalizedMessage());
		} catch (IOException e) {
			throw new WebspaceException(
					ErrorCode.ERROR_CANNOT_REACH_REMOTE_FILE, fileLocation.createFileURI(), e.getLocalizedMessage());

		}
		BufferedInputStream bIn = new BufferedInputStream(in, BUF_SIZE);
		ProgressInputStream pbIn = new ProgressInputStream(bIn,
				fp.contentLength);
		pbIn.setProgressListener( pl );

		InputStream inflater;
		if (fp.contentEncoding.equals("deflate")) {
			inflater = new InflaterInputStream(pbIn);
		} else if (fp.contentEncoding.equals("gzip") || (fp.contentEncoding.equals("identity") && fp.contentType.equals( "application/x-gzip" ))) {
			try {
				inflater = new GZIPInputStream(pbIn);
			} catch (IOException e) {
				throw new WebspaceException( ErrorCode.ERROR_FILE_HAS_GZIP_ERROR, e.getLocalizedMessage() );
			}
		} else
			inflater = pbIn;

		return inflater;
	}

	public void shutdownConnection() {
		client.getConnectionManager().shutdown();
	}

}
